/**
 * 数独图像处理模块
 * 用于定位数独网格并识别其中的数字
 */

/**
 * 检查是否支持OpenCV
 */
function isOpenCVAvailable() {
    try {
        // 尝试导入OpenCV库
        require('opencv4nodejs');
        return true;
    } catch (e) {
        return false;
    }
}

/**
 * 加载OpenCV处理器
 */
function loadOpenCVProcessor() {
    try {
        // 尝试导入自定义OpenCV处理器
        const { OpenCVProcessor } = require('./opencv-processor.js');
        return new OpenCVProcessor();
    } catch (e) {
        console.error('无法加载OpenCV处理器:', e);
        return null;
    }
}

// 检查OpenCV是否可用
const openCVAvailable = isOpenCVAvailable();
let openCVProcessor = null;

if (openCVAvailable) {
    openCVProcessor = loadOpenCVProcessor();
    if (openCVProcessor) {
        console.log('OpenCV处理器已加载');
    } else {
        console.log('OpenCV库可用，但处理器加载失败');
    }
} else {
    console.log('OpenCV库不可用，使用基础图像处理功能');
}

/**
 * 将彩色图像转换为灰度图像
 */
function toGrayscale(imageData) {
    const data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        const red = data[i];
        const green = data[i + 1];
        const blue = data[i + 2];
        // 使用标准灰度转换公式
        const gray = 0.299 * red + 0.587 * green + 0.114 * blue;
        data[i] = gray;
        data[i + 1] = gray;
        data[i + 2] = gray;
    }
    return imageData;
}

/**
 * 图像二值化处理
 */
function applyThreshold(imageData, threshold = 128) {
    const data = imageData.data;
    for (let i = 0; i < data.length; i += 4) {
        const gray = data[i]; // 假设已经是灰度图
        const binaryValue = gray >= threshold ? 255 : 0;
        data[i] = binaryValue;
        data[i + 1] = binaryValue;
        data[i + 2] = binaryValue;
    }
    return imageData;
}

/**
 * 自适应阈值处理
 */
function applyAdaptiveThreshold(imageData) {
    const data = imageData.data;
    const width = imageData.width;
    const height = imageData.height;
    
    // 计算全局平均亮度
    let sum = 0;
    for (let i = 0; i < data.length; i += 4) {
        sum += data[i];
    }
    const average = sum / (data.length / 4);
    
    // 使用平均亮度作为阈值进行二值化，调整阈值以保留更多细节
    return applyThreshold(imageData, average * 0.9); // 降低阈值以保留更多细节
}

/**
 * 增强图像对比度
 */
function enhanceContrast(imageData) {
    const data = imageData.data;
    let min = 255;
    let max = 0;
    
    // 找到图像中的最小和最大亮度值
    for (let i = 0; i < data.length; i += 4) {
        const gray = data[i]; // 假设已经是灰度图
        min = Math.min(min, gray);
        max = Math.max(max, gray);
    }
    
    // 避免除零错误
    const range = max - min;
    if (range === 0) return imageData;
    
    // 增强对比度，使用更强烈的对比度增强
    for (let i = 0; i < data.length; i += 4) {
        const gray = data[i];
        // 将值映射到0-255范围，使用伽马校正增强对比度
        const normalized = (gray - min) / range;
        const enhanced = Math.pow(normalized, 0.8) * 255; // 伽马值0.8增强对比度
        data[i] = enhanced;
        data[i + 1] = enhanced;
        data[i + 2] = enhanced;
    }
    
    return imageData;
}

/**
 * 图像锐化
 */
function sharpenImage(imageData) {
    // 简单的锐化处理
    const data = imageData.data;
    const width = imageData.width;
    const height = imageData.height;
    
    // 创建输出数据副本
    const output = new Uint8ClampedArray(data);
    
    // 简单的3x3锐化卷积核
    const kernel = [
        [0, -1, 0],
        [-1, 5, -1],
        [0, -1, 0]
    ];
    
    // 应用卷积
    for (let y = 1; y < height - 1; y++) {
        for (let x = 1; x < width - 1; x++) {
            let sum = 0;
            for (let ky = -1; ky <= 1; ky++) {
                for (let kx = -1; kx <= 1; kx++) {
                    const pixelIndex = ((y + ky) * width + (x + kx)) * 4;
                    sum += data[pixelIndex] * kernel[ky + 1][kx + 1];
                }
            }
            
            // 限制值在0-255范围内
            const newValue = Math.min(255, Math.max(0, sum));
            const index = (y * width + x) * 4;
            output[index] = newValue;
            output[index + 1] = newValue;
            output[index + 2] = newValue;
        }
    }
    
    // 更新图像数据
    imageData.data.set(output);
    return imageData;
}

/**
 * Sobel边缘检测
 */
function detectEdges(imageData) {
    // 简化实现，实际应用中可以使用更复杂的算法
    return imageData;
}

/**
 * 查找图像中最大的四边形（假设为数独网格边界）
 */
function findLargestQuadrilateral(imageData) {
    // 这是一个简化的实现
    // 实际应用中需要使用轮廓检测来查找四边形
    
    // 假设数独网格位于图像中心附近
    const width = imageData.width;
    const height = imageData.height;
    
    const left = Math.floor(width * 0.1);
    const top = Math.floor(height * 0.1);
    const right = Math.floor(width * 0.9);
    const bottom = Math.floor(height * 0.9);
    
    return {
        topLeft: { x: left, y: top },
        topRight: { x: right, y: top },
        bottomRight: { x: right, y: bottom },
        bottomLeft: { x: left, y: bottom }
    };
}

/**
 * 透视变换，提取网格区域
 */
function perspectiveTransform(imageData, quad) {
    // 简化实现，实际应用中需要进行透视变换计算
    return imageData;
}

/**
 * 将网格分割为81个单元格并识别数字
 */
function extractDigitsFromGrid(imageData) {
    const sudokuMatrix = Array(9).fill().map(() => Array(9).fill(0));
    const cellWidth = Math.floor(imageData.width / 9);
    const cellHeight = Math.floor(imageData.height / 9);
    
    // 简化实现，实际应用中需要进行OCR识别
    // 这里我们返回一个示例数独
    const sampleSudoku = [
        [5, 3, 0, 0, 7, 0, 0, 0, 0],
        [6, 0, 0, 1, 9, 5, 0, 0, 0],
        [0, 9, 8, 0, 0, 0, 0, 6, 0],
        [8, 0, 0, 0, 6, 0, 0, 0, 3],
        [4, 0, 0, 8, 0, 3, 0, 0, 1],
        [7, 0, 0, 0, 2, 0, 0, 0, 6],
        [0, 6, 0, 0, 0, 0, 2, 8, 0],
        [0, 0, 0, 4, 1, 9, 0, 0, 5],
        [0, 0, 0, 0, 8, 0, 0, 7, 9]
    ];
    
    return sampleSudoku;
}

/**
 * 预处理单元格图像以提高OCR准确性
 */
function preprocessCellImage(imageData) {
    // 转换为灰度图
    let processedImage = toGrayscale(imageData);
    
    // 应用自适应阈值二值化
    processedImage = applyAdaptiveThreshold(processedImage);
    
    // 锐化图像
    processedImage = sharpenImage(processedImage);
    
    return processedImage;
}

/**
 * 识别单个单元格中的数字
 */
function recognizeDigit(cellImageData) {
    // 计算图像中白色像素的比例
    const data = cellImageData.data;
    const width = cellImageData.width;
    const height = cellImageData.height;
    let whitePixelCount = 0;
    const totalPixels = width * height;
    
    for (let i = 0; i < data.length; i += 4) {
        const gray = data[i];
        if (gray > 128) { // 白色像素
            whitePixelCount++;
        }
    }
    
    // 如果白色像素比例过小，认为是空单元格
    const whitePixelRatio = whitePixelCount / totalPixels;
    if (whitePixelRatio < 0.05) {
        return 0;
    }
    
    // 这里应该使用OCR引擎识别数字
    // 简化实现，返回随机数字用于测试
    return 0; // 0表示空单元格
}

/**
 * 图像预处理以提高OCR识别准确性 - 针对百度OCR优化
 */
function preprocessImageForOCR(imageData) {
    // 如果OpenCV可用，使用OpenCV进行高级图像处理
    if (openCVProcessor) {
        console.log('使用OpenCV进行图像预处理');
        // 这里应该调用OpenCV处理器的方法
        // 由于是简化实现，我们仍然使用现有的处理方法
    }
    
    // 转换为灰度图
    let processedImage = toGrayscale(imageData);
    
    // 增强对比度
    processedImage = enhanceContrast(processedImage);
    
    // 应用自适应阈值处理
    processedImage = applyAdaptiveThreshold(processedImage);
    
    // 锐化图像
    processedImage = sharpenImage(processedImage);
    
    return processedImage;
}

/**
 * 处理数独图像以提高OCR识别准确性 - 特别优化版
 */
function preprocessSudokuImageForBaiduOCR(imageData) {
    // 转换为灰度图
    let processedImage = toGrayscale(imageData);
    
    // 增强对比度 - 更加强烈的对比度增强
    processedImage = enhanceContrast(processedImage);
    
    // 应用自适应阈值处理 - 调整阈值以更好地识别数字
    processedImage = applyAdaptiveThreshold(processedImage);
    
    // 锐化图像 - 增强边缘以便更好地识别
    processedImage = sharpenImage(processedImage);
    
    return processedImage;
}

/**
 * 针对百度OCR优化的数独图像预处理
 */
function preprocessSudokuImageForBaiduOCROptimized(imageData) {
    // 转换为灰度图
    let processedImage = toGrayscale(imageData);
    
    // 极大地增强对比度
    processedImage = enhanceContrastExtreme(processedImage);
    
    // 应用更严格的二值化处理
    processedImage = applyStrictThreshold(processedImage);
    
    // 锐化图像
    processedImage = sharpenImage(processedImage);
    
    return processedImage;
}

/**
 * 极端对比度增强
 */
function enhanceContrastExtreme(imageData) {
    const data = imageData.data;
    let min = 255;
    let max = 0;
    
    // 找到图像中的最小和最大亮度值
    for (let i = 0; i < data.length; i += 4) {
        const gray = data[i]; // 假设已经是灰度图
        min = Math.min(min, gray);
        max = Math.max(max, gray);
    }
    
    // 避免除零错误
    const range = max - min;
    if (range === 0) return imageData;
    
    // 使用更强的伽马校正增强对比度
    for (let i = 0; i < data.length; i += 4) {
        const gray = data[i];
        // 将值映射到0-255范围，使用伽马校正增强对比度
        const normalized = (gray - min) / range;
        const enhanced = Math.pow(normalized, 0.5) * 255; // 伽马值0.5增强对比度
        data[i] = enhanced;
        data[i + 1] = enhanced;
        data[i + 2] = enhanced;
    }
    
    return imageData;
}

/**
 * 严格阈值处理
 */
function applyStrictThreshold(imageData) {
    const data = imageData.data;
    // 计算全局平均亮度
    let sum = 0;
    for (let i = 0; i < data.length; i += 4) {
        sum += data[i];
    }
    const average = sum / (data.length / 4);
    
    // 使用更高的阈值进行二值化
    return applyThreshold(imageData, average * 1.2);
}

/**
 * 针对数独优化的图像预处理（更强版本）
 */
function preprocessSudokuImageForBaiduOCROptimizedV2(imageData) {
    // 转换为灰度图
    let processedImage = toGrayscale(imageData);
    
    // 极端对比度增强
    processedImage = enhanceContrastExtremeV2(processedImage);
    
    // 自适应阈值处理
    processedImage = applyAdaptiveThreshold(processedImage);
    
    // 锐化图像
    processedImage = sharpenImage(processedImage);
    
    return processedImage;
}

/**
 * 极端对比度增强V2
 */
function enhanceContrastExtremeV2(imageData) {
    const data = imageData.data;
    
    // 计算直方图
    const histogram = new Array(256).fill(0);
    for (let i = 0; i < data.length; i += 4) {
        const gray = data[i];
        histogram[gray]++;
    }
    
    // 计算累积分布函数
    const cdf = new Array(256).fill(0);
    cdf[0] = histogram[0];
    for (let i = 1; i < 256; i++) {
        cdf[i] = cdf[i - 1] + histogram[i];
    }
    
    // 直方图均衡化
    const totalPixels = data.length / 4;
    for (let i = 0; i < data.length; i += 4) {
        const gray = data[i];
        const newGray = Math.floor((cdf[gray] / totalPixels) * 255);
        data[i] = newGray;
        data[i + 1] = newGray;
        data[i + 2] = newGray;
    }
    
    return imageData;
}

// 导出函数
if (typeof module !== 'undefined' && module.exports) {
    module.exports = {
        toGrayscale,
        applyThreshold,
        applyAdaptiveThreshold,
        enhanceContrast,
        sharpenImage,
        detectEdges,
        findLargestQuadrilateral,
        perspectiveTransform,
        extractDigitsFromGrid,
        preprocessCellImage,
        preprocessImageForOCR,
        preprocessSudokuImageForBaiduOCR,
        recognizeDigit,
        isOpenCVAvailable,
        loadOpenCVProcessor
    };
}